﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.Practices.Unity;
using JTLeigh.Commerce.Spencer.Core.Business;
using JTLeigh.Commerce.Spencer.Core.Service.Contracts;
using JTLeigh.Commerce.Spencer.Features.ProductFeedback.Business.Services;

// aliases for entities
using ProductFeedbackE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductFeedback;
using ProductFeedbackBadgeE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductFeedbackBadge;
using ProductFeedbackBadgeAssociationE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductFeedbackBadgeAssociation;
using LocalizedProductRatingAttributeE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.LocalizedProductRatingAttribute;
using ProductRatingAttributeVaueE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductRatingAttributeValue;
using LocalizedProductRecommendationAttributeE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.LocalizedProductRecommendationAttribute;
using ProductRecommendationAttributeVaueE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductRecommendationAttributeValue;
using LocalizedProductReviewAttributeE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.LocalizedProductReviewAttribute;
using ProductReviewAttributeVaueE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductReviewAttributeValue;
using ProductReviewImageE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductReviewImage;
using ProductReviewVideoE = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Common.Entities.ProductReviewVideo;

// aliases for contracts
using GetProductFeedbackRequestC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.GetProductFeedbackRequest;
using GetProductFeedbackResponseC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.GetProductFeedbackResponse;
using ProductFeedbackC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductFeedback;
using ProductFeedbackBadgeC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductFeedbackBadge;
using ProductRatingAttributeC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductRatingAttribute;
using ProductRatingC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductRating;
using ProductRatingAttributeValueC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductRatingAttributeValue;
using ProductRecommendationAttributeC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductRecommendationAttribute;
using ProductRecommendationC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductRecommendation;
using ProductRecommendationAttributeValueC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductRecommendationAttributeValue;
using ProductReviewAttributeC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductReviewAttribute;
using ProductReviewC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductReview;
using ProductReviewAttributeValueC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductReviewAttributeValue;
using ProductReviewImageC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductReviewImage;
using ProductReviewVideoC = JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Contracts.Runtime.GetProductFeedback.ProductReviewVideo;

namespace JTLeigh.Commerce.Spencer.Features.ProductFeedback.Service.Commands.Runtime
{

	/// <summary>
	/// Command for getting all feedback for a single product, including all ratings, 
	/// recommendations, reviews, and relevant attribute metadata.
	/// </summary>
	public class GetProductFeedbackCommand
	{

		#region Properties

		/// <summary>
		/// Gets or sets the product feedback metadata service to use to get product feedback 
		/// metadata.
		/// </summary>
		/// <value>An <see cref="IProductFeedbackMetadataService"/> implementation.</value>
		[Dependency]
		public IProductFeedbackMetadataService ProductFeedbackMetadataService { get; set; }

		/// <summary>
		/// Gets or sets the product feedback service to use to get product feedback.
		/// </summary>
		/// <value>An <see cref="IProductFeedbackRuntimeService"/> implementation.</value>
		[Dependency]
		public IProductFeedbackRuntimeService ProductFeedbackRuntimeService { get; set; }

		#endregion // Properties

		#region Methods

		/// <summary>
		/// Gets all feedback for a single product, including all ratings, recommendations, 
		/// reviews, and relevant attribute metadata.
		/// </summary>
		/// <param name="request">The <see cref="GetProductFeedbackRequestC"/> request object.</param>
		/// <returns>The <see cref="GetProductFeedbackResponseC"/> response object.</returns>
		[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Reviewed, but to be reviewed again later.")]
		public GetProductFeedbackResponseC GetProductFeedback(GetProductFeedbackRequestC request)
		{
			IList<ProductFeedbackE> feedback;
            PaginationResult<ProductFeedbackE> paginationResult;
            PaginationDetail paginationDetail;
            Dictionary<Guid, ProductFeedbackBadgeE> feedbackBadges;
			Dictionary<Guid, LocalizedProductRatingAttributeE> ratingAttributes;
			Dictionary<Guid, LocalizedProductRecommendationAttributeE> recommendationAttributes;
			Dictionary<Guid, LocalizedProductReviewAttributeE> reviewAttributes;
            GetProductFeedbackResponseC response;
			ProductFeedbackC feedbackC;
            ProductFeedbackBadgeC feedbackBadgeC;
			ProductRatingAttributeC ratingAttributeC;
			ProductRatingAttributeValueC ratingAttributeValueC;
			ProductRecommendationAttributeC recommendationAttributeC;
			ProductRecommendationAttributeValueC recommendationAttributeValueC;
			ProductReviewAttributeC reviewAttributeC;
            ProductReviewAttributeValueC reviewAttributeValueC;
            ProductReviewImageC reviewImageC;
            ProductReviewVideoC reviewVideoC;

			feedback = ProductFeedbackRuntimeService.GetProductFeedback(request.TenantId, request.ProductId.CatalogId, request.ProductId.ProductId, request.SelectionBehaviorName);

            if (request.PaginationBehavior != null)
            {
                paginationResult = PaginationTools.Paginate<ProductFeedbackE>(feedback, request.PaginationBehavior.CurrentPage, request.PaginationBehavior.MaximumPages, request.PaginationBehavior.MaximumItemsPerPage);
                feedback = paginationResult.ItemsOnCurrentPage;
                paginationDetail = new PaginationDetail
                {
                    CurrentPage = paginationResult.CurrentPage,
                    TotalPages = paginationResult.TotalPages,
                };
            }
            else
            {
                paginationDetail = null;
            }

            feedbackBadges = ProductFeedbackMetadataService.GetProductFeedbackBadges(request.TenantId, request.ProductId.CatalogId, request.ProductId.ProductId, request.EffectiveDate, feedback);

            ratingAttributes = ProductFeedbackMetadataService.GetProductRatingAttributes(request.TenantId, request.ProductId.CatalogId, request.ProductId.ProductId, request.CultureId, request.EffectiveDate, feedback);

            recommendationAttributes = ProductFeedbackMetadataService.GetProductRecommendationAttributes(request.TenantId, request.ProductId.CatalogId, request.ProductId.ProductId, request.CultureId, request.EffectiveDate, feedback);

            reviewAttributes = ProductFeedbackMetadataService.GetProductReviewAttributes(request.TenantId, request.ProductId.CatalogId, request.ProductId.ProductId, request.CultureId, request.EffectiveDate, feedback);

			response = new GetProductFeedbackResponseC
			{
				Feedback = new List<ProductFeedbackC>(feedback.Count),
                FeedbackBadges = new Dictionary<Guid, ProductFeedbackBadgeC>(feedbackBadges.Count),
				RatingAttributes = new Dictionary<Guid, ProductRatingAttributeC>(ratingAttributes.Count),
				RecommendationAttributes = new Dictionary<Guid, ProductRecommendationAttributeC>(recommendationAttributes.Count),
				ReviewAttributes = new Dictionary<Guid, ProductReviewAttributeC>(reviewAttributes.Count),
                PaginationDetail = paginationDetail,
			};

			foreach (ProductFeedbackE feedbackE in feedback)
			{
				feedbackC = new ProductFeedbackC()
				{
					FeedbackId = feedbackE.FeedbackId,
					CultureId = feedbackE.CultureId,
					DateAdded = feedbackE.DateAdded,
					CustomerId = feedbackE.CustomerId,
					CustomerName = feedbackE.CustomerName,
					CustomerLocation = feedbackE.CustomerLocation,
					EditorComments = feedbackE.EditorComments,
                    BadgeIds = feedbackE.BadgeAssociations.Keys.ToArray(),
				};

				if (feedbackE.Rating != null)
				{
					feedbackC.Rating = new ProductRatingC
					{
						Value = feedbackE.Rating.Value,
                        AttributeValues = new List<ProductRatingAttributeValueC>(feedbackE.Rating.AttributeValues.Values.Count),
					};
					foreach (ProductRatingAttributeVaueE ratingAttributeValueE in feedbackE.Rating.AttributeValues.Values)
					{
						ratingAttributeValueC = new ProductRatingAttributeValueC()
						{
							AttributeId = ratingAttributeValueE.AttributeId,
							Value = ratingAttributeValueE.Value,
						};
						feedbackC.Rating.AttributeValues.Add(ratingAttributeValueC);
					}
				}

				if (feedbackE.Recommendation != null)
				{
					feedbackC.Recommendation = new ProductRecommendationC
					{
						Value = feedbackE.Recommendation.Value,
                        AttributeValues = new List<ProductRecommendationAttributeValueC>(feedbackE.Recommendation.AttributeValues.Values.Count),
					};
					foreach (ProductRecommendationAttributeVaueE recommendationAttributeValueE in feedbackE.Recommendation.AttributeValues.Values)
					{
						recommendationAttributeValueC = new ProductRecommendationAttributeValueC()
						{
							AttributeId = recommendationAttributeValueE.AttributeId,
							Value = recommendationAttributeValueE.Value,
						};
						feedbackC.Recommendation.AttributeValues.Add(recommendationAttributeValueC);
					}
				}

				if (feedbackE.Review != null)
				{
					feedbackC.Review = new ProductReviewC
					{
						Title = feedbackE.Review.Title,
						Body = feedbackE.Review.Body,
						AttributeValues = new List<ProductReviewAttributeValueC>(feedbackE.Review.AttributeValues.Count),
                        Images = new List<ProductReviewImageC>(feedbackE.Review.Images.Count),
						TotalThirdPartyReviews = feedbackE.Review.TotalThirdPartyReviews,
						PositiveThirdPartyReviews = feedbackE.Review.PositiveThirdPartyReviews,
					};
					foreach (ProductReviewAttributeVaueE reviewAttributeValueE in feedbackE.Review.AttributeValues.Values)
					{
						reviewAttributeValueC = new ProductReviewAttributeValueC()
						{
							AttributeId = reviewAttributeValueE.AttributeId,
							Value = reviewAttributeValueE.Value,
						};
						feedbackC.Review.AttributeValues.Add(reviewAttributeValueC);
					}
                    foreach (ProductReviewImageE reviewImageE in feedbackE.Review.Images.Values)
                    {
                        reviewImageC = new ProductReviewImageC()
                        {
                            ImageId = reviewImageE.ImageId,
                            Caption = reviewImageE.Caption,
                            ThumbnailPath = reviewImageE.ThumbnailPath,
                            ThumbnailWidth = reviewImageE.ThumbnailWidth,
                            ThumbnailHeight = reviewImageE.ThumbnailHeight,
                            ImagePath = reviewImageE.ImagePath,
                            ImageWidth = reviewImageE.ImageWidth,
                            ImageHeight = reviewImageE.ImageHeight,
                        };
                        feedbackC.Review.Images.Add(reviewImageC);
                    }
                    if (feedbackE.Review.Video != null)
                    {
                        reviewVideoC = new ProductReviewVideoC()
                        {
                            StillPath = feedbackE.Review.Video.StillPath,
                            StillWidth = feedbackE.Review.Video.StillWidth,
                            StillHeight = feedbackE.Review.Video.StillHeight,
                            VideoPath = feedbackE.Review.Video.VideoPath,
                            VideoWidth = feedbackE.Review.Video.VideoWidth,
                            VideoHeight = feedbackE.Review.Video.VideoHeight,
                            Length = feedbackE.Review.Video.Length,
                            Transcript = feedbackE.Review.Video.Transcript,
                        };
                        feedbackC.Review.Video = reviewVideoC;
                    }
                }

				response.Feedback.Add(feedbackC);
			}

            foreach (ProductFeedbackBadgeE feedbackBadgeE in feedbackBadges.Values)
            {
                feedbackBadgeC = new ProductFeedbackBadgeC()
                {
                    BadgeId = feedbackBadgeE.BadgeId,
                    WellKnownBadgeCode = feedbackBadgeE.WellKnownBadgeCode,
                };
                response.FeedbackBadges.Add(feedbackBadgeC.BadgeId, feedbackBadgeC);
            }

            foreach (LocalizedProductRatingAttributeE ratingAttribute in ratingAttributes.Values)
			{
				ratingAttributeC = new ProductRatingAttributeC()
				{
					AttributeId = ratingAttribute.AttributeId,
					DisplayOrder = ratingAttribute.DisplayOrder,
					Text = ratingAttribute.Text,
				};
				response.RatingAttributes.Add(ratingAttributeC.AttributeId, ratingAttributeC);
			}

			foreach (LocalizedProductRecommendationAttributeE recommendationAttribute in recommendationAttributes.Values)
			{
				recommendationAttributeC = new ProductRecommendationAttributeC()
				{
					AttributeId = recommendationAttribute.AttributeId,
					DisplayOrder = recommendationAttribute.DisplayOrder,
					Text = recommendationAttribute.Text,
				};
				response.RecommendationAttributes.Add(recommendationAttributeC.AttributeId, recommendationAttributeC);
			}

			foreach (LocalizedProductReviewAttributeE reviewAttribute in reviewAttributes.Values)
			{
				reviewAttributeC = new ProductReviewAttributeC()
				{
					AttributeId = reviewAttribute.AttributeId,
					DisplayOrder = reviewAttribute.DisplayOrder,
					Text = reviewAttribute.Text,
				};
				response.ReviewAttributes.Add(reviewAttributeC.AttributeId, reviewAttributeC);
			}

			return response;
		}

		#endregion // Methods

	}

}
